package com.pointlion.back.oa.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.pointlion.back.oa.domain.FlowProcessInstance;
import com.pointlion.back.oa.mapper.FlowProcessMapper;
import com.pointlion.common.constant.BillTypeEnum;
import com.pointlion.common.constant.CommonConstants;
import com.pointlion.common.core.domain.entity.SysUser;
import com.pointlion.common.util.FlowUtil;
import com.pointlion.common.utils.SecurityUtils;
import com.pointlion.system.mapper.SysUserMapper;
import org.flowable.bpmn.model.EndEvent;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.Process;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/***
 * @des
 * @author Ly
 * @date 2023/5/31
 */
@Service
public class FlowProcessInstanceService {

    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private FlowProcessMapper flowProcessMapper;
    @Autowired
    private SysUserMapper sysUserMapper;
    //@Autowired
    //private OaDutyApplyService oaDutyApplyService;
    //@Autowired
    //private OaReimburseApplyService oaReimburseApplyService;
    //@Autowired
    //private OaCustomFormApplyService oaCustomFormApplyService;
    //
    //
    //@Autowired
    //private OaHotelApplyService oaHotelApplyService;
    //@Autowired
    //private OaMeetingroomApplyService oaMeetingroomApplyService;
    //@Autowired
    //private OaTicketApplyService oaTicketApplyService;
    //@Autowired
    //private OaCarApplyService oaCarApplyService;
    //@Autowired
    //private OaSealApplyService oaSealApplyService;
    
    
    
    
    

    /*****
     * 启动流程---入口，调用其他单据类型服务
     * @param ins
     */
    public void submitFlow(FlowProcessInstance ins ){
        //假勤申请
        //if(BillTypeEnum.DUTY_LEAVE.getBillType().equals(ins.getBillType())|| BillTypeEnum.DUTY_OTHERCITYWORK.getBillType().equals(ins.getBillType())|| BillTypeEnum.DUTY_OUT.getBillType().equals(ins.getBillType())|| BillTypeEnum.DUTY_OVERTIME.getBillType().equals(ins.getBillType())|| BillTypeEnum.DUTY_REST.getBillType().equals(ins.getBillType())){
        //    oaDutyApplyService.submitFlow(ins.getBusinessId());
        //}
        //else if(BillTypeEnum.REIMBURSE.getBillType().equals(ins.getBillType())|| BillTypeEnum.REIMBURSE_BUS.getBillType().equals(ins.getBillType())){
        //    oaReimburseApplyService.submitFlow(ins.getBusinessId());
        //}
        //else if(BillTypeEnum.CUSTOM_FORM.getBillType().equals(ins.getBillType())){
        //    oaCustomFormApplyService.submitApply(ins.getBusinessId());
        //}
        //else if(BillTypeEnum.CAR_APPLY.getBillType().equals(ins.getBillType())){
        //    oaCarApplyService.submitFlow(ins.getBusinessId());
        //}
        //
        //else if(BillTypeEnum.HOTEL_APPLY.getBillType().equals(ins.getBillType())){
        //    oaHotelApplyService.submitFlow(ins.getBusinessId());
        //}
        //else if(BillTypeEnum.MEETINGROOM_APPLY.getBillType().equals(ins.getBillType())){
        //    oaMeetingroomApplyService.submitFlow(ins.getBusinessId());
        //}
        //else if(BillTypeEnum.TICKET_APPLY.getBillType().equals(ins.getBillType())){
        //    oaTicketApplyService.submitFlow(ins.getBusinessId());
        //}
        //else if(BillTypeEnum.SEAL_APPLY.getBillType().equals(ins.getBillType())){
        //    oaSealApplyService.submitFlow(ins.getBusinessId());
        //}
        
        //else{
        //    throw new RuntimeException("未匹配到流程，请检查单据类型");
        //}



    }


    /****
     * 取回流程---入口调用其他单据类型服务
     * @param ins
     */
    public void cancleFlow(FlowProcessInstance ins ){
        //假勤申请
        //if(BillTypeEnum.DUTY_LEAVE.getBillType().equals(ins.getBillType())|| BillTypeEnum.DUTY_OTHERCITYWORK.getBillType().equals(ins.getBillType())|| BillTypeEnum.DUTY_OUT.getBillType().equals(ins.getBillType())|| BillTypeEnum.DUTY_OVERTIME.getBillType().equals(ins.getBillType())|| BillTypeEnum.DUTY_REST.getBillType().equals(ins.getBillType())){
        //    oaDutyApplyService.cancleFlow(ins.getBusinessId());
        //}else if(BillTypeEnum.REIMBURSE.getBillType().equals(ins.getBillType())|| BillTypeEnum.REIMBURSE_BUS.getBillType().equals(ins.getBillType())){
        //    oaReimburseApplyService.cancleFlow(ins.getBusinessId());
        //}else if(BillTypeEnum.CUSTOM_FORM.getBillType().equals(ins.getBillType())){
        //    oaCustomFormApplyService.cancleFlow(ins.getBusinessId());
        //}else if(BillTypeEnum.CAR_APPLY.getBillType().equals(ins.getBillType())){
        //    oaCarApplyService.cancleFlow(ins.getBusinessId());
        //}
        //
        //else if(BillTypeEnum.HOTEL_APPLY.getBillType().equals(ins.getBillType())){
        //    oaHotelApplyService.cancleFlow(ins.getBusinessId());
        //}
        //else if(BillTypeEnum.MEETINGROOM_APPLY.getBillType().equals(ins.getBillType())){
        //    oaMeetingroomApplyService.cancleFlow(ins.getBusinessId());
        //}
        //else if(BillTypeEnum.TICKET_APPLY.getBillType().equals(ins.getBillType())){
        //    oaTicketApplyService.cancleFlow(ins.getBusinessId());
        //}
        //else if(BillTypeEnum.SEAL_APPLY.getBillType().equals(ins.getBillType())){
        //    oaSealApplyService.cancleFlow(ins.getBusinessId());
        //}
        //else{
        //    throw new RuntimeException("未匹配到流程，请检查单据类型");
        //}
    }



    /****
     * 流程取回----历史和当前运行都删除
     * @param insId
     */
    @Transactional
    public void cancleProcesInstance(String insId, String deleteReason){
        // 执行此方法后未审批的任务 act_ru_task 会被删除，流程历史 act_hi_taskinst 不会被删除，并且流程历史的状态为finished完成
        // 撤销都删除-----需要先删运行的，再删历史的
        ProcessInstance rins = runtimeService.createProcessInstanceQuery().processInstanceId(insId).singleResult();
        if(rins!=null){
            runtimeService.deleteProcessInstance(insId, deleteReason);
        }

        HistoricProcessInstance his = historyService.createHistoricProcessInstanceQuery().processInstanceId(insId).singleResult();
        if(his!=null){
            historyService.deleteHistoricProcessInstance(his.getId());
        }
    }

    /*****
     * 强制终止流程-----不会删除历史记录，流程会直接结束。（历史记录中的流程也会结束，历史审批信息会保留）
     * @param processInstanceId
     */
    @Transactional
    public void stopProcessInstanceById(String processInstanceId) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (processInstance != null) {
            //1、获取终止节点---任意一个终止节点
            List<EndEvent> endNodes = findEndFlowElement(processInstance.getProcessDefinitionId());
            String endId = endNodes.get(0).getId();
            //2、执行终止----查出所有的执行流（可能有并行的）。所有执行流均跳转到结束节点
            List<Execution> executions = runtimeService.createExecutionQuery().parentId(processInstanceId).list();
            if(executions!=null && executions.size()>0){
                //查出任意一个执行流---设置处理方式为。驳回
                runtimeService.setVariable(executions.get(0).getId(), CommonConstants.FLOW_FINISH_TYPE, CommonConstants.FLOW_FINISH_TYPE_REJECT);
            }
            List<String> executionIds = new ArrayList<>();
            executions.forEach(execution -> executionIds.add(execution.getId()));
            runtimeService.createChangeActivityStateBuilder().moveExecutionsToSingleActivityId(executionIds, endId).changeState();
        }
    }

    /*****
     * 启动流程
     * @param id
     * @param title
     * @param billType
     */
    public ProcessInstance startProcess(Long id,String title,String billType){
        String tableName = BillTypeEnum.getTableName(billType);
        String defKey = BillTypeEnum.getDefKey(billType);
        if(StrUtil.isBlank(tableName)||StrUtil.isBlank(defKey)){
            throw new RuntimeException("单据类型缺少配置信息");
        }
        SysUser user = SecurityUtils.getLoginUser().getUser();
        Map<String,Object> vars = FlowUtil.buildFlowVars(title,user.getUserName(),user.getNickName(),
                DateUtil.formatDateTime(new Date()), CommonConstants.NO);
        ProcessInstance procIns = runtimeService.startProcessInstanceByKey(defKey,billType+":"+tableName+":"+id,vars);

        return procIns;
    }

    /****
     * 查找结束节点
     * @param processDefId
     * @return
     */
    private List findEndFlowElement(String processDefId) {
        Process mainProcess = repositoryService.getBpmnModel(processDefId).getMainProcess();
        Collection<FlowElement> list = mainProcess.getFlowElements();
        if (CollectionUtil.isEmpty(list)) {
            return Collections.EMPTY_LIST;
        }
        return list.stream().filter(f -> f instanceof EndEvent).collect(Collectors.toList());
    }




    /****
     * 清空所有流程实例
     */
    @Transactional
    public void deleteAllProcessInstance(){
        List<HistoricProcessInstance> list =historyService.createHistoricProcessInstanceQuery().list();
        for(HistoricProcessInstance p:list){
            String insId = p.getId();
            ProcessInstance rins = runtimeService.createProcessInstanceQuery().processInstanceId(insId).singleResult();
            if(rins!=null){
                runtimeService.deleteProcessInstance(insId, "清空流程历史记录");
            }
            historyService.deleteHistoricProcessInstance(insId);
        }


    }




}
